/** array.d - Basic operations for internal array

Authors:
	Wei Li (oldrev@gmail.com)

Copyright:
	Copyright (C) 2007 Wei Li.

License:
	BSD

*/


module dotmars.base.collection.array;

import dotmars.base.typetraits;
import dotmars.base.iterator;

////////////////////////////////////////////////////////////////////////////////

private template ArrayIteratorBase()
{
	public alias T	ValueType;
	public alias ValueType* PtrType;

	public const TraversalCategory	TraversalTag = TraversalCategory.RandomAccess;
	public const AccessCategory		AccessTag = AccessCategory.ReadWrite;

	private PtrType	m_ptr = null;

	public static SelfType opCall(PtrType p)
	{
		SelfType it;
		it.m_ptr = p;
		return it;
	}

	public static SelfType opCall(ContainerType arr) {
		SelfType it;
		it.m_ptr = arr.ptr;
		return it;
	}

	public ValueType value() {
		return *m_ptr;
	}

	public void value(ValueType val) {
		*m_ptr = val;
	}

	ValueType opIndex(size_t index) {
		return m_ptr[index];
	}

	bool opEquals(SelfType rhs) { //==
		return m_ptr is rhs.m_ptr;
	}
}

////////////////////////////////////////////////////////////////////////////////

struct ArrayIterator(T)
{
	public alias T[] ContainerType;
	public alias ArrayIterator!(T) SelfType;

	mixin ArrayIteratorBase;

	public SelfType opAddAssign(ptrdiff_t n) { // i+=n
		m_ptr += n;	
		return *this;
	}

	public SelfType opSubAssign(ptrdiff_t n) { //i-=n
		m_ptr -= n;	
		return *this;
	}

	public SelfType opPostInc() { //i++
		return SelfType(m_ptr++);
	}

	public SelfType opPostDec() { //i--
		return SelfType(m_ptr--);
	}

	SelfType opAdd(size_t rhs) {
		return SelfType(m_ptr + rhs);
	}

	SelfType opSub(size_t rhs) {
		return SelfType(m_ptr - rhs);
	}

}


////////////////////////////////////////////////////////////////////////////////

struct ArrayReverseIterator(T)
{
	public alias T[] ContainerType;
	public alias ArrayReverseIterator!(T) SelfType;

	mixin ArrayIteratorBase;

	public SelfType opAddAssign(ptrdiff_t n) { // i+=n
		m_ptr -= n;	
		return *this;
	}

	public SelfType opSubAssign(ptrdiff_t n) { //i-=n
		m_ptr += n;	
		return *this;
	}

	public SelfType opPostInc() { //i++
		return SelfType(m_ptr--);
	}

	public SelfType opPostDec() { //i--
		return SelfType(m_ptr++);
	}

	SelfType opAdd(size_t rhs) { //i+n
		return SelfType(m_ptr - rhs);
	}

	SelfType opSub(size_t rhs) { //i-n
		return SelfType(m_ptr + rhs);
	}
}

////////////////////////////////////////////////////////////////////////////////

ArrayIterator!(T) begin(T)(T[] self) 
in {
	assert(!empty(self));
}
body { 
	return ArrayIterator!(T)(self.ptr);
}

ArrayIterator!(T) end(T)(T[] self) {
	return ArrayIterator!(T)(self.ptr + self.length);
}

ArrayReverseIterator!(T) rbegin(T)(T[] self) 
in {
	assert(!empty(self));
}
body {
	return ArrayReverseIterator!(T)(arr.self + self.length - 1);
}

ArrayReverseIterator!(T) rend(T)(T[] self) {
	return ArrayReverseIterator!(T)(self.ptr - 1);
}

void clear(T)(ref T[] self) {
	self.length = 0;
}

bool empty(T)(T[] self) {
	return self.length == 0;
}

void addLast(T)(ref T[] self, T val) {
	self ~= val;	
}

T first(T)(T[] self) 
in {
	assert(self !is null);
}
body {
	assert(!self.empty());
	return self[0];
}

T last(T)(T[] self) 
in {
	assert(self !is null);
}
body {
	assert(!self.empty());
	return self[self.length - 1];
}

void swap(T)(ref T[] self, ref T[] rhs)
{
	T[] tmp = rhs;
	rhs = self;
	self = rhs;
}
